home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-06-15 | 86.7 KB | 2,812 lines | [TEXT/MPS ] |
- /*---------------------------------------------------------------------------
- FILENAME
- UniversalMessageIntf.c
-
- DESCRIPTION
- This file contains the routines which override the universal imaging
- messages that the ImageWriter LQ utilizes.
-
- COPYRIGHT
- Copyright Apple Computer, Inc. 1992-1994
- All rights reserved.
-
- INTERFACE ROUTINES:
- SD_Initialize
- SD_ShutDown
- SD_JobFormatDialog
- SD_JobFormatModeQuery
- SD_OpenConnection
- SD_StartSendPage
- SD_RenderPage
- SD_DefaultPrinter
- SD_SetupImageData
- SD_FetchTaggedData
- SD_RasterPackageBitmap
- SD_RasterLineFeed
-
- 12/20/93 dmh Sync'd with the shipping 1.0b3 GX driver.
- 8/28/94 dmh Sync'd with the shipping 1.0.1 GX driver.
- 8/28/94 dmh Universalized.
- 6/14/96 cn Updated to support Universal Interfaces 2.1.
-
- -------------------------------------------------------------------------------- */
-
- // Include the standard Mac header files
- #include "MacIncludes.h"
-
- // Include the new QuickDraw GX graphics header files
- #include <GXGraphics.h>
- #include <GraphicsLibraries.h>
- #include <GXMath.h>
- #include <QDLibrary.h>
- #include <FontLibrary.h>
- #include <GXLayout.h>
-
- // Include the required Printing Manager header files
- #include <GXPrinting.h>
- #include <GXPrinterDrivers.h>
- #include <Collections.h>
- #include <GXMessages.h>
- #include <PrintingLibraries.h>
-
- #include <GXExceptions.h>
-
- // Include the internal driver constants and types used by this module
- #include "LQResources.h"
- #include "UniversalMessageIntf.h"
- #include "OldAPIMessageIntf.h"
- #include "DialogRoutines.h"
-
- /***************************************************************************************
- * CONSTANTS *
- ***************************************************************************************/
-
- // ImageWriter LQ device commands
-
- #define kEscape (char) 27 // <Escape> character
- #define kLineFeed (char) 10 // Line feed character
- #define kDevStatusCommand "\033?" // <Escape>? - used to query the status of the printer
-
- #define kLowResGraphicsCommand (char) 'G' // 72 dpi graphics mode
- #define kHighResGraphicsCommand (char) 'C' // 216 dpi graphics mode
-
- #define kLowResMarginsCommand (char) 'F' // 72 dpi margins command
- #define kHighResMarginsCommand (char) 'h' // 216 dpi margins command
-
- #define kSetColorCommand (char) 'K' // Command to select color
-
-
- // Constants used with the ScanLineRecord structure
-
- #define kScanLineHdrSize 15 // Size of the constant portion of the scan line structure
-
-
- /***************************************************************************************
- * TYPES *
- ***************************************************************************************/
-
- // ScanLineRecord - Structure overlayed within a buffer to fill in the comands and data needed to
- // package one complete scan line.
- typedef struct
- {
- char cMarginsEscape; // kEscape character
- char cMarginsCommand; // Set Margins command character
- char cIndentDistance[4]; // Number of pixels to indent
-
- char cColorEscape; // kEscape character
- char cSetColorCommand; // Set color command
- char cColor; // The color to use
-
- char cEscape; // kEscape character
- char cCommand; // Enter graphics mode command
- char cLineStrLength[4]; // number of dots to print
- char iTheData[9072]; // Bits for the data, enough for one line's worth
- } ScanLineRecord,
- *ScanLinePtr;
-
-
- /***************************************************************************************
- * INTERNAL ROUTINES *
- ***************************************************************************************/
-
- /****************************************************************************************
-
- Long2Dec
-
- function:
- This routine converts a long integer into an ASCII string representing the
- numeric value. If the number is less than four digits, then it's padded
- with leading zeros.
-
- parameters:
- theNumber number to convert to a string
- emitStringHere location in which to store the ASCII string
-
- returns:
- none
-
- ****************************************************************************************/
- void Long2Dec(long theNumber, Ptr emitStringHere)
- {
- char aString[10];
- short i;
- short actualWidth;
- short theLength;
-
- NumToString(theNumber, (unsigned char *) aString);
-
- // Get the width of the string, check for being too small
-
- theLength = StrLength(aString);
- actualWidth = theLength;
- if (actualWidth < 4)
- actualWidth = 4;
-
- // output the string, padding with leading zeros
-
- theLength = actualWidth - theLength;
- for (i = 0; i < actualWidth; ++i)
- {
- *emitStringHere++ = (i < theLength) ? '0' : aString[(i + 1) - theLength];
- }
- }
- /* Long2Dec */
-
-
- /****************************************************************************************
-
- PrinterHasColorRibbon
-
- function:
- This routine is a utility function that returns true if the desktop printer
- configuration file specifies that the printer contains a color ribbon, and
- false if it has a black and white ribbon.
-
- parameters:
- None
-
- returns:
- Boolean true => printer has color ribbon; false => black and white ribbon
-
- ****************************************************************************************/
- Boolean PrinterHasColorRibbon(void)
- {
- OSErr anErr;
- Boolean hasColor = true;
- Str32 deviceName;
- IWLQConfigInfoHdl configData;
-
- // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
-
- GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
- if ( StrLength(deviceName) > 0 )
- {
- // if we are going to a particular device, assume no color, as that is more common
- hasColor = false;
-
- anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
- if (anErr == noErr)
- {
- hasColor = (*configData)->hasColorRibbon;
- DisposHandle((Handle) configData);
- }
- }
-
- return(hasColor);
- }
- /* PrinterHasColorRibbon */
-
-
- /****************************************************************************************
-
- PrinterHasTrays
-
- function:
- This routine is a utility function that returns the number of sheet feeder trays
- that are attached to the desktop printer. If no sheet feeder is attached, then
- the function returns zero.
-
- parameters:
- None
-
- returns:
- char number of sheet feeder trays attached to the printer; zero if no sheet feeder
-
- ****************************************************************************************/
- char PrinterHasTrays(void)
- {
- OSErr anErr;
- char numTrays = 0; // Assume no trays available (common case)
- Str32 deviceName;
- IWLQConfigInfoHdl configData;
-
- // if not formatting to a particular device, assume color ribbon, for widest range of colorSpaces
-
- GXGetPrinterName(GXGetJobOutputPrinter(GXGetJob()), deviceName);
- if ( StrLength(deviceName) > 0 )
- {
- anErr = GXFetchDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle *) &configData);
- if (anErr == noErr)
- {
- numTrays = (*configData)->numTrays;
- DisposHandle((Handle) configData);
- }
- }
-
- return(numTrays);
- }
- /* PrinterHasTrays */
-
-
- /****************************************************************************************
-
- UpdateDTPConfigInfo
-
- function:
- This routine is a utility function that queries the printer to determine its
- configuration (color ribbon, trays, etc.) and updates the config info. in the
- desktop printer file to reflect this new configuration.
-
- parameters:
- None
-
- returns:
- OSErr error code
-
- ****************************************************************************************/
- OSErr UpdateDTPConfigInfo(void)
- {
- OSErr anErr;
- IWLQConfigInfoHdl configData;
- char statusString[9];
- long statusStrLength;
- Boolean wasSheetfeederAttached;
- gxJob theJob = GXGetJob();
-
- // Determine if there was a sheetfeeder attached to the printer the last time we updated the config file
- wasSheetfeederAttached = PrinterHasTrays() > 0;
-
- // Make a handle in which to store the config. info.
-
- configData = (IWLQConfigInfoHdl) NewHandleClear( sizeof(IWLQConfigInfo) );
- anErr = MemError();
- require(anErr == noErr, NewHandleClear);
-
- // Now query the printer
-
- statusStrLength = 9;
-
- anErr = Send_GXGetDeviceStatus(kDevStatusCommand, 2, statusString, &statusStrLength, "\p\n");
- require(anErr == noErr, Send_GXGetDeviceStatus);
-
- // Scan the status string returned looking for the needed info.
-
- if ( (statusString[0] == 'L') && (statusString[1] == 'Q') )
- {
- Str32 deviceName;
-
- if ( statusString[3] == 'C' ) // T => Has color ribbon
- {
- (*configData)->hasColorRibbon = true;
- }
-
- if ( (statusString[3] == 'E') ||
- (statusString[3] == 'F')
- ) // T => Sheet feeder is installed
- {
- (*configData)->numTrays = statusString[4] - 0x30;
- }
- else
- if ( (statusString[4] == 'E') ||
- (statusString[4] == 'F')
- ) // T => Sheet feeder is installed
- {
- (*configData)->numTrays = statusString[5] - 0x30;
- }
-
- // Update the config. file with the latest info. (our driver info.)
-
- GXGetPrinterName(GXGetJobOutputPrinter(theJob), deviceName);
- anErr = GXWriteDTPData(deviceName, kIWLQConfigType, kIWLQConfigID, (Handle) configData);
- require(anErr == noErr, WriteDTPData);
-
- // If this is the first time we've detected a sheet feeder, then we must set the tray info. (in the config. file)
- // for the sheet feeder trays. If this isn't the first time we've detected a sheetfeeder, we'll just use
- // the last sheetfeeder tray settings.
-
- if ( (!wasSheetfeederAttached) && ((*configData)->numTrays > 0) ) // T => No sheetfeeder before; clear the tray info.
- {
- GXSetTrayPaperType(1, NULL); /* Reset the paper types from the default tray */
- }
- else if ( wasSheetfeederAttached && ((*configData)->numTrays == 0) ) // T => Sheetfeeder before; clear the tray info.
- {
- GXSetTrayPaperType(1, NULL); /* Reset the paper types from the first tray, ignore the others */
- }
- }
- // else - not an LQ printer so don't change the config file info.
-
- // Dump the confog. data handle
- DisposHandle((Handle) configData);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- WriteDTPData:
- Send_GXGetDeviceStatus:
- DisposHandle((Handle) configData);
-
- NewHandleClear:
- return(anErr);
- }
- /* UpdateDTPConfigInfo */
-
-
- /****************************************************************************************
-
- FixRoundRectangle
-
- function:
- This routine is a utility function which rounds the coordinate values within
- the rectangle passed in.
-
- parameters:
- r rectangle whose coordinates are to be rounded
-
- returns:
- None
-
- ****************************************************************************************/
- void FixRoundRectangle(gxRectangle *r)
- {
- r->top = ff(FixRound(r->top));
- r->left = ff(FixRound(r->left));
- r->bottom = ff(FixRound(r->bottom));
- r->right = ff(FixRound(r->right));
- }
- /* FixRoundRectangle */
-
-
- /****************************************************************************************
-
- JobIsBestQuality
-
- function:
- This routine is called to determine if the job the driver is currently
- processing is to be output in best quality or rough quality. The function
- returns true if best quality, and false otherwise.
-
- parameters:
- None
-
- returns:
- Boolean true if best quality job; false otherwise
-
- ****************************************************************************************/
- Boolean JobIsBestQuality(void)
- {
- OSErr anErr;
- Boolean isFinal;
- gxQualityInfo jobQualitySettings;
- long itemSize = sizeof(jobQualitySettings);
-
- // Retrieve the quality setting info from the job
- anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()), gxQualityTag, gxPrintingTagID, &itemSize, &jobQualitySettings);
- check(anErr == noErr);
-
- isFinal = (anErr == noErr) && (jobQualitySettings.currentQuality == 1);
-
- return(isFinal);
- }
- /* JobIsBestQuality */
-
-
- /****************************************************************************************
-
- MakeNewPrinterViewDevice
-
- function:
- This routine is called to add a new view device to the printer object. The
- viewDevice that's added will have a resolution of 216 dpi, and will have the
- set of colors specified by the theColors parameter. The newly created
- view device is added to the printer object.
-
- parameters:
- thePrinter the newly allocated printer object
- theColors the colors over which the view device is defined
- numColrs the number of colors in the set
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr MakeNewPrinterViewDevice( gxPrinter thePrinter,
- gxSetColor theColors[],
- short numColors)
- {
- OSErr anErr = noErr;
- gxViewDevice vd;
- gxMapping vdMapping;
- gxShape theBitmap;
- gxColorSet theColorSet;
-
- // Create the new viewDevice using a fake bitmap
- {
- gxBitmap aBitmap;
-
- aBitmap.pixelSize = 1;
- aBitmap.rowBytes = 0;
- aBitmap.width = 0;
- aBitmap.height = 0;
- aBitmap.image = (char*)gxMissingImagePointer;
- aBitmap.space = gxNoSpace;
- aBitmap.set = nil;
- aBitmap.profile = nil;
-
- theBitmap = GXNewBitmap(&aBitmap, nil);
- require_action( GXGetGraphicsError(nil) == noErr, NewBitmap, anErr = GXGetGraphicsError(nil); );
-
- vd = GXNewViewDevice(gxScreenViewDevices, theBitmap);
- require_action( GXGetGraphicsError(nil) == noErr, NewViewDevice, anErr = GXGetGraphicsError(nil); );
-
- // Dispose of the reference to the temporary shape
- GXDisposeShape(theBitmap);
- }
-
- // Now set the view device's color space based on the set of colors passed in
- {
- theColorSet = GXNewColorSet(gxRGBSpace, numColors, theColors);
- require_action( GXGetGraphicsError(nil) == noErr, NewColorSet, anErr = GXGetGraphicsError(nil); );
-
- SetViewDeviceColorSet(vd, theColorSet);
- require_action( GXGetGraphicsError(nil) == noErr, SetViewDeviceColorSet, anErr = GXGetGraphicsError(nil); );
-
- // Dispose of the reference to the temporary shape
- GXDisposeColorSet(theColorSet);
- }
-
- // Change the viewDevice mapping to include the scaling factor from 72dpi (screen) to 216 dpi (device).
- {
- ResetMapping(&vdMapping);
- ScaleMapping(&vdMapping, ff(3), ff(3), ff(0), ff(0));
-
- GXSetViewDeviceMapping(vd, &vdMapping);
- }
-
- // Add the newly created viewDevice to the printer object
-
- anErr = GXAddPrinterViewDevice(thePrinter, vd);
- require_action( GXGetGraphicsError(nil) == noErr, AddPrinterViewDevice, anErr = GXGetGraphicsError(nil); );
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- SetViewDeviceColorSet:
- GXDisposeColorSet(theColorSet);
-
- AddPrinterViewDevice:
- NewColorSet:
- GXDisposeViewDevice(vd);
- return(anErr);
-
- NewViewDevice:
- GXDisposeShape(theBitmap);
-
- NewBitmap:
- return(anErr);
- }
- /* MakeNewPrinterViewDevice */
-
-
- /****************************************************************************************
-
- WriteDraftChars
-
- function:
- This routine is called to output a single character in the native set of the
- printer. The draftTable parameter contains long word entries for each possible
- character that can be printed. Each long word entry is composed of two word entries,
- where the first word represents the primary character to output and the second
- word optionally specifies an overstrike character. If an overstrike character
- is specified, then we will overstrike the second character on the first. The format
- of each word is the same and is as follows:
-
- bit 15 - 0 => don't backspace before writing character
- 1 => backspace first before printing the character
-
- bits 14:12 - 0
-
- bits 11:8 - national character set to invoke (e.g. kAmerican)
-
- bits 7:0 - the character to send to the printer (must be != 0 to be output)
-
- parameters:
- draftTable Handle to an array of long word entries that describe how to output
- each printable character in draft mode
- draftChar Pointer to the ASCII characters that are to be output
- numChars Number of characters to be output
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr WriteDraftChars(long **draftTable, unsigned char *draftChar, long numChars)
- {
- OSErr anErr = noErr;
- char outputChars[20]; // a maximum of 20 characters can be generated
- short charCount;
-
- // For each character in the buffer, determine how to map the character to a draft character
- for (; numChars > 0; --numChars, ++draftChar)
- {
- // No characters yet for this output character
- charCount = 0;
-
- // Only consider characters in the printable range
- if (*draftChar >= 0x20)
- {
- unsigned long draftControl = (*draftTable)[*draftChar-0x20]; // Fetch native mode long word corresponding to this character
- unsigned char outChar;
- unsigned char nationalSet;
- short i;
-
- // For each word which composes the native mode long word
- for (i = 1; i >= 0; --i)
- {
- // Should we send a backspace character (to overstrike)?
- if ( (draftControl & 0x80000000) != 0 )
- outputChars[charCount++] = 0x08;
-
- outChar = (draftControl >> 16) & 0xFF;
- if (outChar != 0)
- {
- // Determine the national character set to select
- nationalSet = (draftControl >> 24) & 0xF;
-
- // Is this character in the standard, built-in character set?
- if (nationalSet == kAmerican)
- {
- outputChars[charCount++] = outChar;
- }
- else // T => Must select a foreign language character set
- {
- outputChars[charCount++] = 0x1B;
- outputChars[charCount++] = 0x44;
- outputChars[charCount++] = nationalSet;
- outputChars[charCount++] = 0x00;
- outputChars[charCount++] = outChar;
- outputChars[charCount++] = 0x1B; // We always switch back to the kAmerican character set
- outputChars[charCount++] = 0x5A;
- outputChars[charCount++] = 0x07;
- outputChars[charCount++] = 0x00;
- }
- }
-
- // Take the next (low) word and process it (if we're not all done)
- draftControl <<= 16;
- }
- }
-
- // If we generated any data, send it out now
- if (charCount > 0)
- anErr = Send_GXBufferData(outputChars, charCount, gxNoBufferOptions);
- }
-
- return(anErr);
-
- }
- /* WriteDraftChars */
-
-
- /****************************************************************************************
-
- GetPointerThisBig
-
- function:
- This routine is called to return a pointer (in the heap) to the number of
- bytes specified by numBytes. If the pointer is already large enough, then
- this routine simply returns the existing pointer. Otherwise, it allocates
- a new pointer (possibly disposing of the old one) of the specified size.
-
- parameters:
- theBuff returns a pointer to the allocated buffer
- numBytes required size of the pointer returned (in bytes)
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr GetPointerThisBig(Ptr *theBuff, long numBytes)
- {
- OSErr anErr = noErr;
-
- if (*theBuff != nil)
- {
- if ( GetPtrSize(*theBuff) < numBytes ) // T => Won't be big enough; make a new one
- {
- DisposPtr(*theBuff);
- *theBuff = nil;
- }
- }
-
- if (*theBuff == nil)
- {
- *theBuff = NewPtrClear(numBytes);
- anErr = MemError();
- }
-
- return(anErr);
- }
- /* GetPointerThisBig */
-
-
- /****************************************************************************************
-
- GetTextAndPosition
-
- function:
- This routine is called to return information about the layout shape
- referenced by the theShape parameter. It returns a pointer to the
- text data in theChars, the number of characters in the data in numChars, and
- a pointer to the positions of the characters in textPositions. The caller
- is responsible for disposing of the pointers returned in theChars and
- textPositions.
-
- parameters:
- theShape reference to the shape to be examined
- theChars returns a pointer to the text characters
- numChars returns the number of characters in the text shape
- textPosition returns the position of the layout shape
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr GetTextAndPosition( gxShape theShape,
- Ptr *theChars,
- long *numChars,
- gxPoint *textPosition)
- {
- OSErr anErr = noErr;
- long textStrLength;
-
- // Determine the size of the text data and the position of the text
- textStrLength = GXGetLayout(theShape, nil, nil, nil, nil, nil, nil, nil, nil, textPosition);
-
- // Make sure we have a buffer pointer large enough to hold all of the data
-
- anErr = GetPointerThisBig(theChars, textStrLength);
- require(anErr == noErr, CantAllocTextBuff);
-
- // Now we retrieve the text
- GXGetLayout(theShape, *theChars, nil, nil, nil, nil, nil, nil, nil, nil);
-
- // Remember the number of characters in the shape
- *numChars = textStrLength;
-
-
- /******* Clean-up *******/
-
- CantAllocTextBuff:
- return(anErr);
- }
- /* GetTextAndPosition */
-
-
- /****************************************************************************************
-
- PrintPageInDraftMode
-
- function:
- This routine is called to print a page using the native character set in the
- printer. The page to print is referenced by the thePage parameter. The routine
- walks through the picture looking for layout shapes. Each of these
- shapes is imaged using the native character set; all other shapes are ignored.
- This routine assumes the shapes within the picture are y-sorted.
-
- parameters:
- thePage Reference to the page shape that's to be printed
- imageData pointer to the raster image data
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr PrintPageInDraftMode(gxShape thePage, gxRasterImageDataHdl imageData)
- {
- OSErr anErr = noErr;
- long i;
- long numItems;
- Fixed currYPos = ff(0);
- Ptr theChars = nil;
- long numChars = 0;
- gxPoint textPosition;
- Fixed oldTextSize = ff(0);
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Since the page picture we need to process is a picture shape that's embedded in
- // thePage (a shape containing one item => a picture), we need to extract the real
- // page picture from thePage.
-
- thePage = GetPictureItem(thePage, 1, nil, nil, nil, nil);
- numItems = GXGetPicture(thePage, nil, nil, nil, nil);
-
- // For each shape within the picture, check its type and process it accordingly
-
- for (i = 1; i <= numItems; ++i)
- {
- gxShape theShape;
- short theType;
-
- theShape = GetPictureItem(thePage, i, nil, nil, nil, nil);
- theType = GXGetShapeType(theShape);
-
- if (theType == gxLayoutType) // T => We have a layout shape
- {
- Fixed textSize;
- char buff[12];
- char theFace;
- short cmndBuffSz;
-
- // First determine the style in which we're printing
-
- theFace = GetStyleCommonFace( GXGetShapeStyle(theShape) );
-
- buff[0] = kEscape;
- if ( (theFace & bold) != 0 ) // T => Turn bold facing on
- buff[1] = '!';
- else // T => Turn it off
- buff[1] = '"';
-
- buff[2] = kEscape;
- if ( (theFace & underline) != 0 ) // T => Turn underline facing on
- buff[3] = 'X';
- else // T => Turn it off
- buff[3] = 'Y';
-
- cmndBuffSz = 4;
-
- // Next determine if we need to change the size of the font being used
-
- textSize = GXGetShapeTextSize(theShape);
- if (textSize != oldTextSize) // T => Must issue LQ command to change font size
- {
- buff[4] = kEscape; // The first escape command selects black color
- buff[5] = kSetColorCommand;
- buff[6] = '0';
-
- buff[7] = kEscape; // The second escape command selects a draft font
- buff[8] = 'a';
- buff[9] = '1';
-
- buff[10] = kEscape; // The third escape command selects the character pitch
-
- if ( textSize <= ff(10) ) // T => Select 10 cpi
- {
- buff[11] = 'N';
- }
- else // T => All other sizes get mapped to 12 cpi
- {
- buff[11] = 'E';
- }
-
- // Remember the last text size
- oldTextSize = textSize;
-
- // Adjust the size of the data to be sent to the printer
- cmndBuffSz += 8;
- }
- // else - no change in font size
-
- // Send the commands to the printer
- anErr = Send_GXBufferData(buff, cmndBuffSz, gxDontSplitBuffer);
- require(anErr == noErr, CantSendFontCmnd);
-
- // Get the ASCII text and the starting position of the data
- anErr = GetTextAndPosition(theShape, &theChars, &numChars, &textPosition);
- require(anErr == noErr, CantGetTextAndPos);
-
- if ( (currYPos != ff(0)) && (currYPos != textPosition.y) ) // T => Moving to a lower line, finish the last ;line with a CR
- {
- char c = 0x0D;
-
- anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
- require(anErr == noErr, CantSendCRCmnd);
- }
-
- // Position the print head to the proper location on the page
- {
- gxMapping theMapping;
- long lineFeedSize;
- Str255 positionCmndsBuff;
- unsigned long bytesInBuff = 0;
- char *p;
-
- GXGetShapeMapping(theShape, &theMapping);
- MapPoints(&theMapping, (long) 1, &textPosition); // Just map the first point
-
- // Now position the print head vertically
-
- lineFeedSize = (textPosition.y - currYPos) >> 16;
- anErr = Send_GXRasterLineFeed(&lineFeedSize, (char *) positionCmndsBuff, &bytesInBuff, imageData);
- require(anErr == noErr, CantEmitLineFeeds);
-
- // Update the current Y position pointer on the page
- currYPos = textPosition.y;
-
- // Now position the print head horizontally on the page
-
- p = (char *) &positionCmndsBuff[bytesInBuff];
- *p++ = kEscape;
- *p++ = kLowResMarginsCommand;
- Long2Dec((*hGlobals)->leftMargin + FixedToInt(textPosition.x), p); // Convert left margin into ASCII and place it at the start of the scan line
-
- // Update the number of bytes in the buffer
- bytesInBuff += 6;
-
- // Send the positioning info to the printer
- anErr = Send_GXBufferData((char *) positionCmndsBuff, bytesInBuff, gxDontSplitBuffer);
- require(anErr == noErr, CantSendPositionCmnds);
- }
-
- // Now we send the text data to the printer
- anErr = WriteDraftChars((long **) (*hGlobals)->draftTable, (unsigned char *) theChars, numChars);
- require(anErr == noErr, CantWriteChars);
- }
- } // for
-
- // Send one last CR to wrap the last line (if there was one)
- {
- char c = 0x0D;
-
- anErr = Send_GXBufferData(&c, 1, gxNoBufferOptions);
- }
-
-
- /******* Clean-up *******/
-
- CantWriteChars:
- CantSendPositionCmnds:
- CantEmitLineFeeds:
- CantSendCRCmnd:
- CantGetTextAndPos:
- CantSendFontCmnd:
- if (theChars != nil)
- DisposPtr(theChars);
-
- return(anErr);
- }
- /* PrintPageInDraftMode */
-
-
- /***************************************************************************************
- * INTERFACE ROUTINES *
- ***************************************************************************************/
-
- /****************************************************************************************
-
- SD_Initialize
-
- function:
- This routine is called when a new job is created to perform some job-oriented
- task, such as conducting dialogs, spooling, and imaging. It allocates the
- driver's globals handle and initializes it.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_Initialize(void)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals;
-
- // Allocate the driver's global handle
-
- hGlobals = (SpecGlobalsHdl) NewHandleClear(kSpecGlobalsRecLen);
- anErr = MemError();
- require(anErr == noErr, NewHandleClear);
-
- // Tell the Printing Manager to save our globals handle for us
- SetMessageHandlerInstanceContext(hGlobals);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- NewHandleClear:
- return(anErr);
- }
- /* SD_Initialize */
-
-
- /****************************************************************************************
-
- SD_ShutDown
-
- function:
- This routine is called when a job-oriented task has completed and the
- message chain is being destroyed. This routine disposes of the driver's
- globals handle..
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_ShutDown(void)
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Dump the draft table if we loaded it
- if ( (*hGlobals)->draftTable != nil )
- DisposHandle((*hGlobals)->draftTable);
-
- // Dump the driver's globals handle if it was allocated
- if (hGlobals != nil)
- DisposHandle((Handle) hGlobals);
-
- // Make sure the Printing Manager no longer has a reference to our globals handle
- SetMessageHandlerInstanceContext(nil);
-
- return(noErr);
- }
- /* SD_ShutDown */
-
-
- /****************************************************************************************
-
- SD_JobFormatDialog
-
- function:
- This routine is called when the Printing Manager is called to display the
- Job Format dialog. This message gives the driver the opportunity to determine
- the job format modes that are supported by the application. If the application
- supports text, then we set the preferred job format mode to be 'text'. The preferred
- format mode is the format mode that becomes active when the user selects Direct
- Mode from the Job Format dialog box.
-
- parameters:
- dlgResult result of dismissing the dialog (ok or cancel)
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_JobFormatDialog(gxDialogResult *dlgResult)
- {
- OSErr anErr;
- gxJobFormatModeTableHdl theJobFormatModeList;
- gxJob theJob = GXGetJob();
-
- // Did the application specify any job format modes?
-
- anErr = GXGetAvailableJobFormatModes(&theJobFormatModeList);
- if ( (anErr == noErr) && (theJobFormatModeList != nil) )
- {
- long i;
-
- // Examine each job format mode to determine if 'text' mode is supported. If
- // it is, then we make it the preferred format mode for Direct Mode printing
-
- for (i = 0; i <= (*theJobFormatModeList)->numModes - 1; ++i)
- {
- if ((*theJobFormatModeList)->modes[i] == gxTextJobFormatMode)
- {
- // Tell Printing Manger we support 'text' Direct Mode, but that we also
- // support other modes.
-
- GXSetPreferredJobFormatMode(gxTextJobFormatMode, false);
- break;
- }
- }
-
- // Dump the temporary handle we were issued
- DisposHandle((Handle)theJobFormatModeList);
- }
-
- // New we let the dialog be displayed.
-
- anErr = Forward_GXJobDefaultFormatDialog(dlgResult);
- require(anErr == noErr, Forward_GXJobFormatDialog);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- Forward_GXJobFormatDialog:
- return(anErr);
- }
- /* SD_JobFormatDialog */
-
-
- /****************************************************************************************
-
- SD_JobPrintDialog
-
- function:
- This routine is called when the Printing Manager is called to display the
- Job dialog. This message gives the driver the opportunity to add the LQ Options
- panel to the dialog. This panel provides the user the option to choose between
- bidirectional and unidirectional printing.
-
- parameters:
- dlgResult result of dismissing the dialog (ok or cancel)
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_JobPrintDialog(gxDialogResult *dlgResult)
- {
- OSErr anErr;
- gxPanelSetupRecord thePanelInfo;
- long headMotionSize;
- Collection jobCollection;
- HeadMotionJobItem theMotion;
-
- // Get a reference to the job's collection
- jobCollection = GXGetJobCollection( GXGetJob() );
-
- // See if the head motion collection item exists. It the item already exists, then
- // we'll use the last settings.
-
- headMotionSize = sizeof(HeadMotionJobItem);
- anErr = GetCollectionItem (jobCollection,
- kDrvrCreatorType,
- kHeadMotionItemIndex,
- &headMotionSize,
- &theMotion);
-
- if (anErr == collectionItemNotFoundErr) // T => Item doesn't exist; add it
- {
- theMotion.direction = doUnidirectional;
-
- anErr = AddCollectionItem( jobCollection,
- kDrvrCreatorType,
- kHeadMotionItemIndex,
- sizeof(HeadMotionJobItem),
- &theMotion);
- require(anErr == noErr, AddCollectionItem);
- }
- else
- require(anErr == noErr, CantGetCollection);
-
- // Before allowing the Printing Manager to display the dialog, we must first add
- // our panel to the dialog. We do this by appropriately filling in the PanelSetupRecord
- // and then telling the Printing Manager to add our panel to the dialog.
-
- // Initialize the dialog panel structure
- thePanelInfo.panelResId = kLQOptionsPanl; // Resource ID of the 'panl' resource
- thePanelInfo.resourceRefNum = GXGetMessageHandlerResFile();
- thePanelInfo.refCon = 0;
- thePanelInfo.panelKind = gxDriverPanel;
-
- // Add the dialog panel to the Print dialog
-
- GXSetupDialogPanel(&thePanelInfo);
- anErr = GXGetJobError( GXGetJob() );
- require(anErr == noErr, SetupDialogPanel);
-
- // Now we let the dialog be displayed.
-
- anErr = Forward_GXJobPrintDialog(dlgResult);
- check(anErr == noErr);
-
-
- /******* Clean-up *******/
-
- Forward_GXJobPrintDialog:
- SetupDialogPanel:
- CantGetCollection:
- AddCollectionItem:
- return(anErr);
- }
- /* SD_JobPrintDialog */
-
-
- /****************************************************************************************
-
- SD_JobFormatModeQuery
-
- function:
- This routine is called when an application calls JobFormatModeQuery to determine
- the format modes that are available from the driver. This message gives the
- driver the opportunity to determine the type of format mode query the driver
- is requesting and responds to it with the appropriate data.
-
- parameters:
- theQuery type of query to perform
- srcData source data (varies depending upon the type of query)
- dstData destination data (varies depending upon the type of query)
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_JobFormatModeQuery(gxQueryType theQuery, void *srcData, void *dstData)
- {
- OSErr anErr = noErr;
- Handle theFonts;
- Handle theStyles;
-
- check(dstData != nil);
-
- // What type of query is being requested?
- switch(theQuery)
- {
- case gxSetStyleJobFormatCommonStyleQuery:
- {
- char *pStyleName;
-
- // Fetch the list of supported styles
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
- require(anErr == noErr, FailedToLoadStyles1);
-
- HNoPurge(theStyles);
- HLock(theStyles);
-
- // Determine which style is being referenced and set the corresponding style (only 2 styles
- // are currently supported)
-
- if (**((short **) theStyles) == 2) // T => We have the correct number of styles
- {
- char whichFace = 0;
-
- pStyleName = ((char *) *theStyles) + sizeof(short);
-
- if ( IUCompString((unsigned char const *) pStyleName, (unsigned char const *) srcData) == 0 ) // T => They want bold face
- {
- whichFace = bold;
- }
- else
- {
- // Point to the next name in the list
- pStyleName += *pStyleName + 1;
-
- if ( IUCompString((unsigned char const *) pStyleName, (unsigned char const *) srcData) == 0 ) // T => They want underline face
- {
- whichFace = underline;
- }
- }
-
- // If the client specified a valid face, set it now
- if (whichFace != 0)
- {
- SetStyleCommonFace((gxStyle) dstData, GetStyleCommonFace((gxStyle) dstData) | whichFace);
- }
- }
- // else - something is wrong with our resource
-
- // Dump the temporary handle
- DisposHandle(theStyles);
-
- break;
- }
-
- case gxGetJobFormatFontCommonStylesQuery:
- {
- short numStyles;
- short i;
- char *pStyleName;
-
- // Fetch the list of supported styles
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeStylesID, &theStyles);
- require(anErr == noErr, FailedToLoadStyles2);
-
- HNoPurge(theStyles);
- HLock(theStyles);
-
- // Determine the number of styles in the list
- numStyles = **((short **) theStyles);
-
- if (*(Handle *)dstData != nil) // T => Resize the handle to hold info. on the styles
- SetHandleSize(*(Handle *)dstData, sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
- else
- *(Handle *)dstData = NewHandle(sizeof(gxStyleNameTable) + ((numStyles - 1) * sizeof(Str255)));
-
- anErr = MemError();
- require(anErr == noErr, StyleTableResizeFailed);
-
- // Now extract the name of each of the supported fonts
-
- for (i = 1, pStyleName = ((char *) *theStyles) + sizeof(short); i <= numStyles; ++i, pStyleName += *pStyleName + 1)
- {
- BlockMove(pStyleName, (*((gxStyleNameTableHdl) *(Handle *)dstData))->styleNames[i - 1], *pStyleName + 1);
- }
-
- (*((gxStyleNameTableHdl) *(Handle *)dstData))->numStyleNames = numStyles;
-
- // Dump the temporary handle
- DisposHandle(theStyles);
-
- break;
- }
-
- case gxGetJobFormatLineConstraintQuery: // This type of query is not supported
- if (*(Handle *)dstData != nil)
- SetHandleSize(*(Handle *)dstData, 0); // Don't return any data
- break;
-
- case gxGetJobFormatFontsQuery:
- {
- short numFonts;
- short i;
- char *pFontName;
-
- // Fetch the list of supported fonts
-
- anErr = Send_GXFetchTaggedDriverData('STR#', kFormatModeFontsID, &theFonts);
- require(anErr == noErr, FailedToLoadFonts);
-
- HNoPurge(theFonts);
- HLock(theFonts);
-
- // Determine the number of fonts in the list
- numFonts = **((short **) theFonts);
-
- if (*(Handle *)dstData != nil) // T => Resize the handle to hold info. on the fonts
- SetHandleSize(*(Handle *)dstData, sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
- else
- *(Handle *)dstData = NewHandle(sizeof(gxFontTable) + ((numFonts - 1) * sizeof(gxFont)));
-
- anErr = MemError();
- require(anErr == noErr, FontTableResizeFailed);
-
- // Now generate a reference to each of the supported fonts
-
- for (i = 1, pFontName = ((char *) *theFonts) + sizeof(short); i <= numFonts; ++i, pFontName += *pFontName + 1)
- {
- gxFont thisFont;
- gxFontTable *pFontTable;
-
- thisFont = FindPNameFont(gxFullFontName, (unsigned char const *) pFontName);
-
- pFontTable = *((gxFontTableHdl) *(Handle *)dstData);
- pFontTable->fonts[i - 1] = thisFont;
- }
-
- (*((gxFontTableHdl) *(Handle *)dstData))->numFonts = numFonts;
-
- // Dump the temporary handle
- DisposHandle(theFonts);
-
- break;
- }
-
- case gxGetJobFormatFontConstraintQuery:
- {
- gxPositionConstraintTable *pPositionTable;
-
- if ( *(Handle *)dstData != nil) // T => Resize the handle to hold info. on position constraints
- SetHandleSize(*(Handle *)dstData, sizeof(gxPositionConstraintTable) + sizeof(Fixed));
- else
- *(Handle *)dstData = NewHandle( sizeof(gxPositionConstraintTable) + sizeof(Fixed) );
-
- pPositionTable = *((gxPositionConstraintTableHdl) *(Handle *)dstData);
-
- pPositionTable->phase.x = 0; // Start at the top left corner of the page
- pPositionTable->phase.y = 0;
- pPositionTable->offset.x = ff(12); // Indent from the top left by a six lines per inch margin
- pPositionTable->offset.y = ff(12);
- pPositionTable->numSizes = 2; // Two font sizes supported
- pPositionTable->sizes[0] = ff(10); // 10 pitch
- pPositionTable->sizes[1] = ff(12); // 12 pitch
-
- break;
- }
- } // switch
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- StyleTableResizeFailed:
- DisposHandle((Handle) theStyles);
- return(anErr);
-
- FontTableResizeFailed:
- DisposHandle((Handle) theFonts);
-
- FailedToLoadStyles1:
- FailedToLoadStyles2:
- FailedToLoadFonts:
- return(anErr);
- }
- /* SD_JobFormatModeQuery */
-
-
- /****************************************************************************************
-
- SD_OpenConnection
-
- function:
- This routine is called when the Printing Manager sends the OpenConnection
- message. We take this opportunity to open a connection to the printer and
- query the printer to determine its configuration (e.g. color ribbon, trays, etc.).
- We then save the configuration information in the desktop printer file.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_OpenConnection(void)
- {
- OSErr anErr;
-
- // Try to open the connection
-
- anErr = Forward_GXOpenConnection();
- require(anErr == noErr, Forward_GXOpenConnection);
-
- // Query the printer so we can update the configuration information
-
- anErr = UpdateDTPConfigInfo();
- require(anErr == noErr, UpdateDTPConfigInfo);
-
- return(anErr);
-
-
- /******* Clean-up *******/
-
- UpdateDTPConfigInfo:
- Send_GXCleanupOpenConnection();
-
- Forward_GXOpenConnection:
- return(anErr);
- }
- /* SD_OpenConnection */
-
-
- /****************************************************************************************
-
- SD_CleanupOpenConnection
-
- function:
- This routine is called when the Printing Manager sends the CleanupOpenConnection
- message. It's initiated by our SD_OpenConnection routine when we cannot query
- the printer after opening the connection. We simply forward the message along to
- allow others in the message chain to cleanup.
-
- parameters:
- None
-
- returns:
- OSErr
-
- ****************************************************************************************/
- void SD_CleanupOpenConnection(void)
- {
- // Just forward along the message
- Forward_GXCleanupOpenConnection();
- }
- /* SD_CleanupOpenConnection */
-
-
- /****************************************************************************************
-
- SD_StartSendPage
-
- function:
- This routine is called by the Printing Manager to signal the start of sending
- a new page to the printer. If it's a manual feed job, then we alert the user
- to make sure the paper is in the printer. If the printer has trays attached,
- then this routine determines from which tray to feed the paper and then sends
- the appropriate tray selection command to the printer. The tray to pull the
- paper from has already been determined by this time by the Universal Driver.
- The Job collection contains the index of the tray to pull from.
-
- parameters:
- pageFormat format for the page to print
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_StartSendPage (gxFormat pageFormat)
- {
- OSErr anErr;
- Collection jobCollection;
- gxStatusRecord *pStatus;
- gxTrayFeedInfo trayFeedInfo;
- long itemSize = sizeof(trayFeedInfo);
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Get a reference to the job's collection
- jobCollection = GXGetJobCollection( GXGetJob() );
-
- // Determine if this is a manual feed page
-
- anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- nrequire(anErr, GetCollectionItem);
-
- if (trayFeedInfo.manualFeedThisPage) // T => Alert the user to place the paper into the printer
- {
- gxManualFeedRecord *mfeedInfo;
- gxPaperType thePaperType;
-
- // Wait for all IO to complete, so that we can correctly tell the user what to do.
- // Since the WriteData message makes sure all data is flushed before performing the
- // IO, this call insures that pending IO is complete.
-
- anErr = Send_GXWriteData(nil, 0);
- nrequire(anErr, FlushAllData);
-
- // Now we set-up to alert the user to put paper into the printer
-
- pStatus = (gxStatusRecord *) NewPtrClear(sizeof(gxStatusRecord) + sizeof(gxManualFeedRecord));
- anErr = MemError();
- require(anErr == noErr, NewPtrClear);
-
- // Initialize the appropriate fields within the status record
-
- pStatus->statusOwner = 'univ';
- pStatus->statResId = gxUnivAlertStatusResourceId;
- pStatus->statResIndex = gxUnivManualFeedIndex;
- pStatus->bufferLen = sizeof(gxManualFeedRecord);
-
- mfeedInfo = (gxManualFeedRecord *) &pStatus->statusBuffer;
- mfeedInfo->canAutoFeed = true;
- GXGetPaperTypeName(thePaperType = GXGetFormatPaperType(pageFormat), mfeedInfo->paperTypeName);
-
- // Now display the alert to the user. Continue alerting until the user clicks OK, he cancels
- // printing, or some other fatal error happens
- do
- {
- // Issue the alert to the user
- anErr = GXAlertTheUser(pStatus);
- }
- while ( (anErr == noErr) && (pStatus->dialogResult == 0) );
-
- // Based upon the users response, we continue, cancel, or switch to auto-feed
-
- switch (pStatus->dialogResult)
- {
- case ok: // Assume the user loaded the paper
- break;
-
- case cancel: // User cancelled the job; make sure the error code is set
- anErr = gxPrUserAbortErr;
- break;
-
- case gxAutoFeedButtonId: // User wishes to do the remainder of the job with auto-feed. Update job to
- // reflect auto-feed.
-
- {
- gxPaperFeedInfo paperFeed;
-
- /* Update for job */
- paperFeed.autoFeed = true;
- (void) AddCollectionItem(jobCollection, gxPaperFeedTag, gxPrintingTagID, sizeof(paperFeed), &paperFeed);
- }
-
- /* Update as it may be reused */
- trayFeedInfo.manualFeedThisPage = false; /* Other trayInfo fields are still valid */
- (void) AddCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, sizeof(trayFeedInfo), &trayFeedInfo);
-
- /* Can pass paper type reference as this IS device communication time */
- anErr = Send_GXCheckStatus((Ptr) &thePaperType, sizeof(thePaperType), 0, 'univ');
- ncheck(anErr);
-
- /* Update gxTrayFeedInfo.feedTrayIndex for below */
- itemSize = sizeof(trayFeedInfo);
- if (! anErr)
- anErr = GetCollectionItem(jobCollection, gxTrayFeedTag, gxPrintingTagID, &itemSize, &trayFeedInfo);
- break;
- }
-
- // Dump the status record
- DisposPtr((Ptr) pStatus);
- }
-
- require(anErr == noErr, UserAborted);
-
- // At this point we determine if there are trays attached, and if so, we need
- // to issue a command to the printer to select from the proper tray.
-
- if ( PrinterHasTrays() > 0 ) // T => Printer does have trays attached
- {
- gxTrayIndex whichTray;
- char cmndBuff[3];
- TraySettingsJobItem oldAppTraySettings;
-
- // We first determine if we're printing from an old application or a new application because
- // the setting of which tray to use will be determined from different information. To see if
- // we are printing an old app. document, we look for the kTraySettingsItemIndex collection item.
-
- itemSize = sizeof(TraySettingsJobItem);
- if ( GetCollectionItem( GXGetJobCollection(GXGetJob()), kDrvrCreatorType, kTraySettingsItemIndex, &itemSize, &oldAppTraySettings) == noErr )
- {
- if ( (*hGlobals)->pagePrinting == 1 ) // T => Printing the first page
- {
- whichTray = oldAppTraySettings.firstPageFromTray - 1; // Must be zero based
- }
- else // T => Printing some other page
- {
- whichTray = oldAppTraySettings.remainingFromTray - 1; // Must be zero based
- }
- }
- else // T => New app so get tray settings from the 'tray' collection item
- {
- // The trayFeedInfo specifies which tray to select the paper from.
- whichTray = trayFeedInfo.feedTrayIndex - 1; // Must be zero based
- }
-
- // Compose the tray selection command
-
- cmndBuff[0] = kEscape;
- cmndBuff[1] = '@';
- cmndBuff[2] = whichTray + 0x30; // Force to an ACSII number
-
- // Send the command to the printer
- anErr = Send_GXBufferData(cmndBuff, 3, gxNoBufferOptions);
- require(anErr == noErr, BufferData);
- }
-
- // Update the status information to tell the user that we're sending data to the printer
-
- anErr = GXReportStatus(kDriverStatusID, kSendingPartOfPageStatIdx);
- require(anErr == noErr, ReportStatus);
-
- // Now forward the message to others in the chain
-
- anErr = Forward_GXStartSendPage(pageFormat);
- check(anErr == noErr);
-
-
- /******* Cleanup *******/
-
- ReportStatus:
- BufferData:
- UserAborted:
- NewPtrClear:
- FlushAllData:
- GetCollectionItem:
- return(anErr);
- }
- /* SD_StartSendPage */
-
-
- /****************************************************************************************
-
- SD_ImagePage
-
- function:
- This routine is called by the Printing Manager to signal the start of imaging
- a new page to the printer. We take this opportunity to remember which page is
- being printed. This inforamtion is later used by SD_StartSendPage to control
- the input tray selection for documents which are printed from old applications.
-
- parameters:
- theFormat format for the page being rendered
- theShape shape representing the page
- pageInfo information about the page being rendered
- imageData pointer to the raster image data
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_ImagePage ( gxSpoolFile theFile,
- long pageNumber,
- gxFormat theFormat,
- gxRasterImageDataHdl imageData)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- // Remember which page of the document we're currently imaging
- (*hGlobals)->pagePrinting = pageNumber;
-
- // Send the message along to others in the chain
- anErr = Forward_GXImagePage(theFile, pageNumber, theFormat, imageData);
- check(anErr == noErr);
-
- return(anErr);
- }
- /* SD_ImagePage */
-
-
- /****************************************************************************************
-
- SD_RenderPage
-
- function:
- This routine is called by the Printing Manager to signal the start of sending
- a new page to the printer. If it's a manual feed job, then we alert the user
- to make sure the paper is in the printer. Next we set the printer's left margin
- and then we're set to begin printing the page.
-
- parameters:
- theFormat format for the page being rendered
- theShape shape representing the page
- pageInfo information about the page being rendered
- imageData pointer to the raster image data
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_RenderPage (gxFormat theFormat,
- gxShape thePage,
- gxPageInfoRecord *pageInfo,
- gxRasterImageDataHdl imageData)
- {
- OSErr anErr;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
- gxRectangle paperSize;
-
- // Find out how big our paper is
- GXGetFormatDimensions(theFormat, nil, &paperSize);
-
- // Determine the left margin (in pixels)
- {
- SpecGlobalsPtr pGlobals;
- gxRasterImageDataPtr pImageData;
-
- pImageData = *imageData;
- pGlobals = *hGlobals;
- if ( -(paperSize.left) < ff(18) ) // T => IW LQ's can't go tighter than .25 inch
- paperSize.left = -(ff(18));
-
- pGlobals->leftMargin = FixedToInt( FixMul(-paperSize.left, FixDiv(pImageData->hImageRes, ff(72)) ) );
- }
-
- // If not text mode, image the page the normal raster way (via SD_RasterPackageBitmap). We
- // must however set the size of the page and position the paper (with line feeds) to get to
- // the proper "top-of-form".
-
- if ( GXGetJobFormatMode(GXGetJob()) != gxTextJobFormatMode )
- {
- Str255 formStrLength; // should be more than big enough for form skipping
- char aNumber[8];
- char len = 0;
- short formLen; // form length (in 144 dpi)
- short i;
-
- // Force the current line position to be the top of form (assumes the user has positioned the
- // paper properly by this time)
-
- formStrLength[len++] = kEscape;
- formStrLength[len++] = 'v';
-
- // Now we want to skip down the page past the top margin. This will put us in a position to
- // output the first bands of data.
-
- formLen = FixedToInt( FixMul(-paperSize.top, ff(2)) ); // length is set in 144 dpi
- if (formLen > 0)
- {
- // send multiples of 99 since this is the maximum line feed spacing we can have
- if (formLen >= 99)
- {
- formStrLength[len++] = kEscape;
- formStrLength[len++] = 'T';
- formStrLength[len++] = '9';
- formStrLength[len++] = '9';
- do
- {
- formStrLength[len++] = kLineFeed; // line feed
-
- formLen -= 99;
- }
- while (formLen >= 99);
- }
-
- // Send remaining line feeds to position to the top of the printable page
- if (formLen > 0)
- {
- formStrLength[len++] = kEscape;
- formStrLength[len++] = 'T';
- NumToString(formLen, (unsigned char *) aNumber);
- if ( StrLength(aNumber) == 1 )
- {
- formStrLength[len++] = '0';
- formStrLength[len++] = aNumber[1];
- }
- else
- {
- formStrLength[len++] = aNumber[1];
- formStrLength[len++] = aNumber[2];
- }
- formStrLength[len++] = kLineFeed; // line feed
- }
- }
-
- // Now we must specify the paper length based upon the paper size asociated with the format
-
- formStrLength[len++] = kEscape;
- formStrLength[len++] = 'H';
-
- formLen = FixedToInt( FixMul(paperSize.bottom - paperSize.top, ff(2)) ); // length is set in 144 dpi
- NumToString(formLen, (unsigned char *) aNumber);
- for (i = 0; i < 4-aNumber[0]; ++i)
- formStrLength[len++] = '0';
- for (i = 1; i <= aNumber[0]; ++i)
- formStrLength[len++] = aNumber[i];
-
- // Send out the line feeds and the paper size specifier
- anErr = Send_GXBufferData((char *) &formStrLength[0], len, gxNoBufferOptions);
- require(anErr == noErr, SetFormStrLength);
-
- // Now forward the message to others in the chain
-
- anErr = Forward_GXRenderPage(theFormat, thePage, pageInfo, imageData);
- require(anErr == noErr, Forward_GXRenderPage);
- }
- else // T => Doing draft (i.e. direct mode) print job; we do all the rendering
- {
- anErr = PrintPageInDraftMode(thePage, imageData);
- }
-
-
- /******* Cleanup *******/
-
- SetFormStrLength:
- Forward_GXRenderPage:
- return(anErr);
- }
- /* SD_RenderPage */
-
-
- /****************************************************************************************
-
- SD_DefaultPrinter
-
- function:
- This routine is called when a new printer object is being created as a
- result of someone having called NewJob. This message gives the driver the
- opportunity to add any information we want to the new printer object. In
- this case, we add a new black and white viewDevice to the printer object
- which will allow the client application to format a document for this
- specific device at 216 dpi. If the printer has a color ribbon attachment,
- then we create a second view device at 216 dpi which supports eight
- colors.
-
- parameters:
- thePrinter the newly allocated printer object
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DefaultPrinter(gxPrinter thePrinter)
- {
- OSErr anErr;
- gxSetColor theColors[8];
- gxSetColor *pColor;
-
- // First we let others in the chain default the printer object before we do.
-
- anErr = Forward_GXDefaultPrinter(thePrinter);
- require(anErr == noErr, Forward_GXDefaultPrinter);
-
- // Add the standard black and white view device to the printer object
-
- // First set up the color set
- pColor = &theColors[0];
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF; // white
- pColor++;
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000; // black
-
- // Now add the view device
- anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 2);
- require(anErr == noErr, MakeBWViewDevice);
-
- // Does the printer have a color ribbon installed?
- if ( PrinterHasColorRibbon() )
- {
- // Add the standard color view device to the printer object
-
- // First set up the color set
- //
- // Color Index R G B
- // white 0 0xFFFF 0xFFFF 0xFFFF
- // yellow 1 0xFFFF 0xFFFF 0x0000
- // magenta 2 0xFFFF 0x0000 0xFFFF
- // red 3 0xFFFF 0x0000 0x0000
- // cyan 4 0x0000 0xFFFF 0xFFFF
- // green 5 0x0000 0xFFFF 0x0000
- // blue 6 0x0000 0x0000 0xFFFF
- // black 7 0x0000 0x0000 0x0000
-
- pColor = &theColors[0];
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0xFFFF; pColor++; // white
- pColor->rgb.red = pColor->rgb.green = 0xFFFF; pColor->rgb.blue = 0x0000; pColor++; // yellow
- pColor->rgb.red = pColor->rgb.blue = 0xFFFF; pColor->rgb.green = 0x0000; pColor++; // magenta
- pColor->rgb.red =0xFFFF; pColor->rgb.blue = pColor->rgb.green = 0x0000; pColor++; // red
- pColor->rgb.green = pColor->rgb.blue = 0xFFFF; pColor->rgb.red = 0x0000; pColor++; // cyan
- pColor->rgb.red = pColor->rgb.blue = 0x0000; pColor->rgb.green = 0xFFFF; pColor++; // green
- pColor->rgb.red = pColor->rgb.green = 0x0000; pColor->rgb.blue = 0xFFFF; pColor++; // blue
- pColor->rgb.red = pColor->rgb.green = pColor->rgb.blue = 0x0000; // black
-
- // Now add the view device
- anErr = MakeNewPrinterViewDevice(thePrinter, theColors, 8);
- require(anErr == noErr, MakeColorViewDevice);
- }
-
- /******* Clean-up *******/
-
- MakeColorViewDevice:
- MakeBWViewDevice:
- Forward_GXDefaultPrinter:
- return(anErr);
- }
- /* SD_DefaultPrinter */
-
- /****************************************************************************************
-
- SD_DefaultFormat
-
- function:
- This routine is called when a new format is being created as a result of someone
- having called NewFormat. It is also called to sync up the viewDevices with the
- collection's quality mode.
-
- parameters:
- theFormat the format being defaulted
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DefaultFormat(gxFormat theFormat)
- {
- OSErr anErr;
- Handle jobQualitySettingsHdl;
-
- anErr = Forward_GXDefaultFormat(theFormat);
-
- // now, if the application has set up a special formatting mode, we need to update
- // the quality mode collection item (and any private ones we use)
- if (anErr == noErr)
- {
- gxPoint dpiPoint;
- gxMapping vdMapping;
- gxViewDevice selectedDevice = GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 0);
-
- dpiPoint.x = ff(72);
- dpiPoint.y = ff(72);
-
- if (selectedDevice != GXGetPrinterViewDevice(GXGetJobPrinter(GXGetFormatJob(theFormat)), 1) )
- {
- GXGetViewDeviceMapping(selectedDevice, &vdMapping);
- MapPoints(&vdMapping, 1, &dpiPoint);
-
- {
- gxQualityInfo *qualitySettings;
- Collection jobCollection = GXGetJobCollection(GXGetJob());
-
- jobQualitySettingsHdl = NewHandle(0);
- anErr = MemError();
- nrequire(anErr, FailedNewHandle);
-
- anErr = GetCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- if (anErr == collectionItemNotFoundErr)
- {
- Str255 bestString, roughString;
- Size count1, count2;
- Ptr p;
-
- GetIndString( bestString, kQualityID, kBestString);
- GetIndString( roughString, kQualityID, kRoughString);
-
- SetHandleSize(jobQualitySettingsHdl,(sizeof(gxQualityInfo) + bestString[0] + roughString[0] + 2 ));
- anErr = MemError();
- nrequire( anErr, FailedSetHandleSize );
-
- qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
-
- qualitySettings->disableQuality = false;
- qualitySettings->defaultQuality = 1;
- qualitySettings->currentQuality = 1;
- qualitySettings->qualityCount = 2;
-
- count1 = bestString[0]+1;
- p = qualitySettings->qualityNames;
- BlockMove( bestString, p, count1 );
-
- count2 = roughString[0]+1;
- p += count1;
- BlockMove( roughString, p, count2 );
-
- }
- else
- qualitySettings = *((gxQualityInfo **) jobQualitySettingsHdl);
-
- qualitySettings->currentQuality =
- (dpiPoint.y > ff(200)) ? (qualitySettings->qualityCount-1) : 0;
-
- anErr = AddCollectionItemHdl ( jobCollection,
- gxQualityTag,
- gxPrintingTagID,
- jobQualitySettingsHdl );
-
- if (anErr == noErr)
- (void) SetCollectionItemInfo(jobCollection, gxQualityTag, gxPrintingTagID, 0x0000FFFF, gxVolatileOutputDriverCategory);
-
- DisposHandle(jobQualitySettingsHdl);
- }
-
- }
-
- }
-
- FailedNewHandle:
- return(anErr);
-
- FailedSetHandleSize:
- DisposHandle(jobQualitySettingsHdl);
- return(anErr);
-
- }
- /* SD_DefaultFormat */
-
- /****************************************************************************************
-
- SD_DefaultJob
-
- function:
- This routine is called when a new job is being created as a result of someone
- having called NewJob. The driver takes this opportunity to add a default
- head motion collection item to the job.
-
- parameters:
- theJob the job being defaulted
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DefaultJob()
- {
- OSErr anErr;
- gxJob theJob = GXGetJob();
-
- // First forward the default job message along
- anErr = Forward_GXDefaultJob();
- require(anErr == noErr, Forward_GXDefaultJob);
-
- // Add the default collection item which specifies the desired head motion.
- {
- HeadMotionJobItem theMotion;
-
- theMotion.direction = doUnidirectional;
-
- anErr = AddCollectionItem( GXGetJobCollection(theJob),
- kDrvrCreatorType,
- kHeadMotionItemIndex,
- sizeof(HeadMotionJobItem),
- &theMotion);
- check(anErr == noErr);
- }
-
-
- /******* Clean-up *******/
-
- Forward_GXDefaultJob:
- return(anErr);
- }
- /* SD_DefaultJob */
-
-
- /****************************************************************************************
-
- SD_SetupImageData
-
- function:
- This routine is called when the Printing Manager wants us to initialize any
- constant data that's used to image the entire job. This driver takes this
- opportunity to massage the raster image data
-
- parameters:
- hImageData Handle to the raster imaging data
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
- {
- OSErr anErr;
- Boolean isJobNotFinalQuality;
- Boolean isTextJobFormatMode;
- gxRasterImageDataPtr pImageData;
- HeadMotionJobItem theMotion;
- long headMotionSize;
- gxJob theJob = GXGetJob();
-
- // Let others in the message chain do their SetupImageData function
- anErr = Forward_GXSetupImageData(hImageData);
- require(anErr == noErr, Forward_GXSetupImageData);
-
- // Determine if we're to do "final" quality
- isJobNotFinalQuality = !JobIsBestQuality();
-
- // Fetch the head motion job collection item to determine the head motion we should be using
-
- headMotionSize = sizeof(HeadMotionJobItem);
- anErr = GetCollectionItem (GXGetJobCollection(theJob),
- kDrvrCreatorType,
- kHeadMotionItemIndex,
- &headMotionSize,
- &theMotion);
- check(anErr == noErr);
-
- if (anErr != noErr) // T => Default to unidirectional printing => better quality
- {
- theMotion.direction = doUnidirectional;
- anErr = noErr;
- }
-
- // Determine if we are to perform draft mode printing
- isTextJobFormatMode = ( GXGetJobFormatMode(theJob) == gxTextJobFormatMode );
-
- // If the job is not final quality or using textJobFormatMode, downgrade the imaging data to lower quality
- if (isJobNotFinalQuality || isTextJobFormatMode)
- {
- pImageData = *hImageData;
-
- // Image at 72 dpi
- pImageData->hImageRes = ff(72);
- pImageData->vImageRes = ff(72);
-
- // If we're in draft mode, we need to load the draft table to know how to print all possible characters
- if (isTextJobFormatMode)
- {
- Handle draftTable;
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- anErr = Send_GXFetchTaggedDriverData('idft', gxPrintingDriverBaseID, &draftTable);
- require(anErr == noErr, FailedToLoadDraftTable);
-
- // Save the draft table handle in our globals
- (*hGlobals)->draftTable = draftTable;
- }
- else // T => We need to setup better low resolution halftones
- {
- short plane;
-
- // Use halftones that will look better at 72 dpi resolution than our default values.
-
- // Use the same angle and frequency for all planes, because orderDitherDot
- // won't moire on us
- for (plane = 0; plane < 4; ++plane)
- {
- pImageData->theSetup.planeSetup[plane].planeHalftone.angle = ff(0);
- pImageData->theSetup.planeSetup[plane].planeHalftone.frequency = ff(9);
- pImageData->theSetup.planeSetup[plane].planeHalftone.method = gxDispersedDot;
- }
- }
-
- // Determine the StartSendPage command string to use depending upon whether the user choose birdirectional or
- // unidirectional motion.
-
- if (isJobNotFinalQuality)
- {
- // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
- // or unidirectional string)
-
- if ( theMotion.direction == doUnidirectional )
- pImageData->packageControls.startPageStringID = kLowResUniDirID;
- else
- pImageData->packageControls.startPageStringID = kLowResBiDirID;
- }
-
- // Update the packaging data to reflect the lower resolution
- pImageData->packagingInfo.headHeight = 8; // 8 pins (instead of 24)
- pImageData->packagingInfo.numberPasses = 1; // in 1 head pass
- pImageData->packagingInfo.passOffset = 0; // with no space between passes
- }
- else // T => Final quality job
- {
- pImageData = *hImageData;
-
- // Tell the Printing Manager which "start send page" string to send to the device (the bidirectional
- // or unidirectional string)
-
- if ( theMotion.direction == doUnidirectional )
- pImageData->packageControls.startPageStringID = kHighResUniDirID;
- else
- pImageData->packageControls.startPageStringID = kHighResBiDirID;
-
- // image at 216 dpi
- pImageData->hImageRes = ff(216);
- pImageData->vImageRes = ff(216);
- }
-
- // If the printer doesn't have a color ribbon, set up for black and white printing
- if ( !PrinterHasColorRibbon() )
- {
- pImageData = *hImageData;
-
- // one plane, no color flags, move the halftone info up into correct position
- pImageData->theSetup.planes = 1;
- pImageData->packagingInfo.colorPasses = 1;
- pImageData->packagingInfo.packageOptions = 0;
- pImageData->theSetup.planeSetup[0] = pImageData->theSetup.planeSetup[3];
- pImageData->theSetup.planeSetup[0].planeHalftone.tinting = gxLuminanceTint;
- pImageData->theSetup.planeSetup[0].planeHalftone.tintSpace = gxRGBSpace;
- }
-
-
- /******* Clean-up *******/
-
- FailedToLoadDraftTable:
- Forward_GXSetupImageData:
- return(anErr);
- }
- /* SD_SetupImageData */
-
-
- /****************************************************************************************
-
- SD_FetchTaggedData
-
- function:
- This routine is called by the Printing Manager when a resource is fetched
- from some resource file. This driver overrides this message to determine
- when someone is fetching the 'cust' resource. If this resource
- is being fetched, and the job we're processing is not best quality, then
- we lower the resolution in the 'cust' resource handle returned to be 72 dpi.
- This ensures the translation from QuickDraw to QuickDraw GX is done at the
- proper resolution.
-
- parameters:
- rsrcType type of the resource being retrieved
- rsrcID resource ID of the resource being retrieved
- theRsrc handle to the resource retrieved
- owner indicates who is issuing the request; only look at owners == 'drvr'
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_FetchTaggedData(ResType rsrcType, short rsrcID, Handle *theRsrc, OSType owner)
- {
- OSErr anErr;
-
- if (owner == 'drvr') // T => Fetching a driver resource
- {
- if ( (rsrcType == gxTrayCountDataType) && // T => type is trayCountData
- (rsrcID == gxTrayCountDataID) // T => ID is trayCountData
- )
- {
- // Remap as required
- rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFeederRsrcID : kDefaultTrayRsrcID);
- }
- else if ( (rsrcType == gxTrayNameDataType) && // T => type is trayName
- (rsrcID == kDefaultSheetFdrTray1NameID) // T => ID is trayData
- )
- {
- // Remap as required
- rsrcID = ((PrinterHasTrays() > 0) ? kDefaultSheetFdrTray1NameID : kDefaultTrayNameID);
- }
- }
-
- // First fetch the actual resource
- anErr = Forward_GXFetchTaggedData(rsrcType, rsrcID, theRsrc, owner);
- require(anErr == noErr, FetchTaggedData);
-
- if ( (owner == 'drvr') && // T => Fetching a driver resource
- (rsrcType == gxCustType) && // T => type is 'cust'
- (rsrcID == gxCustID) && // T => ID is -8192
- !JobIsBestQuality() // T => Doing rough output
- )
- {
- gxCustomizationHdl custData;
-
- // Change the 'cust' resolution to specify low res translation from QuickDraw to QuickDraw GX
- (*custData)->horizontalResolution = 72;
- (*custData)->verticalResolution = 72;
- }
-
-
- /******* Clean-up *******/
-
- FetchTaggedData:
- return(anErr);
- }
- /* SD_FetchTaggedData */
-
-
- /****************************************************************************************
-
- SD_DefaultDesktopPrinter
-
- function:
- This routine is called by the Printing Manager when a new desktop printer is
- created. We take this opportunity to open a connection to the LQ printer to
- see how it's configured. Specifically, we determine if there are trays
- attached and if there is a color ribbon installed. Based upon the device query,
- we update the desktop printer file.
-
- parameters:
- printerName Name of the printer being created
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DefaultDesktopPrinter(Str31 printerName)
- {
- OSErr anErr;
-
- // First let the Printing Manager create the desktop printer
- anErr = Forward_GXDefaultDesktopPrinter(printerName);
- require(anErr == noErr, DefaultDesktopPrinter);
-
- // Optional step (now removed): during creation of the printer we could open a connection
- // to get the current configuration. However, this has the disadvantage of making the user
- // wait until the printer is available. The user can force a configuration update by printing
- // any document to the printer (even a blank one)
-
- // Now we attempt to open a connection to the device (it will update the config. file)
- // anErr = Send_GXOpenConnection();
- // require(anErr == noErr, OpenConnection);
-
- // A side effect of opening the connection will be that we will have already updated
- // the configuration information (in the file) that specifies whether a color ribbon
- // is installed and the number of sheet feeder trays attached (if any). ## The only additional
- // thing we'd want to do here is to update the number of trays specified in the desktop
- // printer file to be the actual number of trays attached to the device. Currently, the
- // system assumes the number of trays attached is equivalent to the number of default
- // trays specified in our driver resources. Though we can query the printer for the
- // exact number of trays, we cannot update the info. in the config. file that specifies
- // the exact number of trays. We need a RemoveTrayInfo routine.
-
- // Now we just close down the connection
- // anErr = Send_GXCloseConnection();
- // check(anErr == noErr);
-
-
- /******* Clean-up *******/
-
- OpenConnection:
- DefaultDesktopPrinter:
- return(anErr);
- }
- /* SD_DefaultDesktopPrinter */
-
-
- /****************************************************************************************
-
- SD_GetDTPMenuList
-
- function:
- NOOP.
-
- parameters:
- hMenu Handle to the menu that's being built
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_GetDTPMenuList(MenuHandle hMenu)
- {
- return(Forward_GXGetDTPMenuList(hMenu));
- }
- /* SD_GetDTPMenuList */
-
-
- /****************************************************************************************
-
- SD_DTPMenuSelect
-
- function:
- This routine is called by the Printing Manager when a menu item in the Finder's
- Printer menu is selected. This routine determines if the menu item selected
- is the "Input Tray…" item. If it's, then display the dialog which lets the user
- specify the paper in the LQ's sheet feeder if we know there are some trays
- attached to the printer. Otherwise, we just pass the item on to others in the chain.
-
- parameters:
- itemNum Menu item number that was selected
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_DTPMenuSelect(short itemNum)
- {
- OSErr anErr;
-
- if ((itemNum == gxInputTraysMenuItem) && (PrinterHasTrays() > 0)) // T => User wants to configure the input trays
- {
- anErr = DoSheetfeederDialog();
-
- }
- else // T => We didn't process the item
- {
- // Pass the message on to others in the chain
- anErr = Forward_GXDTPMenuSelect(itemNum);
- }
-
- check(anErr == noErr);
-
- return(anErr);
- }
- /* SD_DTPMenuSelect */
-
-
- /****************************************************************************************
-
- SD_RasterPackageBitmap
-
- function:
- This routine is called by the Printing Manager when it has completed rendering
- a single portion of a raster page and the driver should now package the data
- and output it to the device. This routine is called to package one complete band.
-
- It routine does the following:
-
- 1) Starts filling the buffer from buffer + bufferPos. Remember
- that this pointer may not be word aligned - so be careful
- assigning things into it.
-
- 2) Puts a "fake" set of set margins commands at
- the begining of the data. Since most of the time we don't
- know the margins, we save away the value of the bufferPos,
- and backpatch it after we have finished with the bitmap.
-
- 3) Adds in the rotated data for your printer. The data to stuff starts
- at location pPackage->startRaster * pPackage->bitmapToPackage->rowBytes (startY)
- in the pPackage->bitmapToPackage bitmap. Stuffs the bits from here until
- we reach startY + <the band size>, which is the size of our single
- band in this resolution mode. Increment our number by
- <your pass offset> + 1, which is the number of microspaces
- we will send between head passes to form this band. Take care
- that we don't step off of the end of the bitmap in this operation,
- since we may be called with startY at the end of the offscreen if the first part
- of the band is white.
-
- colorBand contains the color band which we should be stuffing, from
- 1 to the number of color passes our printer needs (4).
- Packs in the correct color band. The packager will call us once
- for each color band, and correctly handle line feeds and backward
- line feeds to do the correct thing. If your printer takes full
- RGB or CYMK data, define your number of colors to be
- 1 and pack the full RGB or CYMK data with the one call.
-
- If you request kSendAllColors in your raster pack resource, then this
- message will always be called for all color passes, even those that
- do not have data on them. For some printers, this is useful. For the
- case of the ImageWriter, this option is not specified, so this message
- will only be sent for colors that actually have dirty bits within them.
-
- 4) Backpatches SetMargins from the saved value in step 2) now that we
- know the margins.
-
- 5) Increments bufferPos by the number of bytes we have
- added to the buffer. Be sure to take into account the Set Margins
- command.
-
- parameters:
- whatToPackage info. about the bitmap whose data is to be sent to the printer
- buffer buffer in which to place the packaged data
- bufferPos position within buffer of where to place the packaged data
- imageData handle to the raster image data info.
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_RasterPackageBitmap( gxRasterPackageBitmapRec *whatToPackage,
- Ptr buffer,
- unsigned long *bufferPos,
- gxRasterImageDataHdl imageData)
- {
- OSErr anErr = noErr;
- ScanLinePtr pTheScanLine; // Pointer to the start of scan line data
- unsigned short firstDirty; // First dirty pixel
- Boolean bandIsDirty; // Is this band dirty?
- unsigned short whichCol; // Index into the scan line data of where to place the next data bytes
- unsigned short x;
- unsigned long tempColumn; // Placeholder for the column of data we're currently assembling
- // for 72 dpi: only high order byte is used
- // for 216 dpi: highest order three bytes are used
- Ptr basePtr; // Pointer to current X byte
- unsigned char outputMask; // Mask of bit to set in rotated image
- unsigned char inputMask; // Mask of bit to look at in X
- unsigned short yPointerOffset; // Increment pointer by this to get to next scanline
- unsigned short endY; // Last scan line to examine (top-to-bottom)
- unsigned short endX; // Last pixel column to examine (left-to-right)
- unsigned short incrY; // Number of scan lines to increment by when advancing to the next scan line
- short bytesPerBand; // Number of bytes in a single band (1 for 72 dpi, 3 for 216 dpi)
-
-
- // Determine the number of bytes that are in a single band
- if ( (*imageData)->hImageRes == ff(72) ) // T => Low resolution output
- bytesPerBand = 1;
- else
- bytesPerBand = 3;
-
- // Overlay a scan line structure on the buffer we're filling in
- pTheScanLine = (ScanLinePtr) (buffer + *bufferPos);
-
- // Set color mode for this scan line, if needed
-
- pTheScanLine->cColorEscape = kEscape;
- pTheScanLine->cSetColorCommand = kSetColorCommand;
-
- if ( (*imageData)->packagingInfo.colorPasses == 4 ) // T => Doing four pass color output
- {
- switch (whatToPackage->colorBand) // Determine which color to select
- {
- case 1: // yellow
- pTheScanLine->cColor = '1';
- break;
-
- case 2: // magenta
- pTheScanLine->cColor = '2';
- break;
-
- case 3: // cyan
- pTheScanLine->cColor = '3';
- break;
-
- case 4: // black
- pTheScanLine->cColor = '0';
- break;
- }
- }
- else // T => Just doing black and white printing; select the color black
- pTheScanLine->cColor = '0';
-
- // We start out with no dirty bits
- firstDirty = 0;
- bandIsDirty = false;
-
- // Set our array index to zero
- whichCol = 0;
-
- // Get the byte pointer for the start of this color band
- basePtr = whatToPackage->bitmapToPackage->image;
-
- // Get the byte pointer for the start of the first scan line
- basePtr += whatToPackage->startRaster * whatToPackage->bitmapToPackage->rowBytes;
-
- // Save away loop invariants
-
- endY = whatToPackage->startRaster + (*imageData)->packagingInfo.headHeight; // Ending Y scan line
- incrY = (*imageData)->packagingInfo.passOffset + 1; // Number of scanlines to increment by
- endX = whatToPackage->dirtyRect.right; // Ending X pos
- yPointerOffset = incrY * whatToPackage->bitmapToPackage->rowBytes; // amount to add to the input pointer to move to the next scanline
-
- // If the ending position is too large for the bitmap we have been given,
- //truncate it, so that we don't print garbage
-
- if (endY > whatToPackage->bitmapToPackage->height)
- endY = whatToPackage->bitmapToPackage->height;
-
- // Start with the first bit in the byte sub-band
- inputMask = 0x80;
-
- // For the entire width of the scan line, move a rolling mask along in the
- // X direction, rotating up 8 or 24 bits of Y data per column.
-
- for (x = 0; x < endX; x++)
- {
- Ptr thePtr;
-
- // The bits in this column are clear to begin with
- tempColumn = 0;
-
- // Which byte(s) to look at in the input buffer
- thePtr = basePtr;
-
- // For the number of bytes in a single band, scan through each single
- // byte sub-band, setting each of the 8 bits = the bit in that scan line
- {
- short bitsPerByte;
- short byteSubBand = bytesPerBand;
- unsigned char *currByte = (unsigned char *) &tempColumn;
- short currYPos;
-
- currYPos = whatToPackage->startRaster;
-
- do
- {
- // Where to place the bit in the output. The LQ takes the bit pattern upside down.
- outputMask = 0x01;
-
- bitsPerByte = 8;
- while ( (bitsPerByte > 0) && (currYPos < endY) )
- {
- // If we have a bit turned on in the input, rotate it into the output
- if ( ((*thePtr) & inputMask) != 0 )
- *currByte |= outputMask;
-
- // move onto next position in the output data
- outputMask <<= 1;
-
- // move onto the next scan line in the input data
- thePtr += yPointerOffset;
-
- // Indicate we processed one of the bits
- bitsPerByte--;
-
- // Keep track of our Y position as we move down the column
- currYPos += incrY;
- }
-
- if (currYPos >= endY) // T => We're done with this column
- break;
-
- // Indicate we processed one of the byte rows in the band
- byteSubBand--;
-
- // Bump to the next byte to fill in tempColumn
- currByte++;
- }
- while (byteSubBand > 0);
- }
-
- // Save the column info (a max. of three bytes). Note: we'll only advance whichCol based upon the number of bytes per band
- BlockMove((Ptr) &tempColumn, (Ptr) &(pTheScanLine->iTheData[whichCol]), 3);
-
- // If we have some form of data, then mark that this band is dirty
- if (tempColumn != 0)
- {
- if (!bandIsDirty) // T => Not already dirty; remember the first dirty pixel
- {
- /* These are the first dirty pixels we have seen so far */
- bandIsDirty = true;
- firstDirty = x;
- }
- }
-
- // If we have some dirty bits, adjust the whichCol variable based upon the number of bytes in a band
- if (bandIsDirty)
- {
- // Move on to the next column or set of columns
- whichCol += bytesPerBand;
- }
-
- // Position for the next bit in the input byte currently referenced by basePtr
- inputMask >>= 1;
-
- if (inputMask == 0) // T => Need to reset the input mask and advance the pointer
- {
- // Get the next byte
- basePtr++;
-
- // Reset the bit mask to the first bit
- inputMask = 0x80;
- }
- } // end of loop for width of bitmap
-
- // If we have a dirty band, fill in the left margin setting and add a carriage return to the end
- if (bandIsDirty)
- {
- // Set the left margin to be the first dirty pixel in the scan line
- {
- SpecGlobalsHdl hGlobals = GetMessageHandlerInstanceContext();
-
- check(hGlobals);
-
- // Stuff in the set margin command
-
- pTheScanLine->cMarginsEscape = kEscape;
- pTheScanLine->cMarginsCommand = (bytesPerBand == 1) ? kLowResMarginsCommand : kHighResMarginsCommand;
-
- // Convert left margin into ASCII and place it at the start of the scan line
- Long2Dec((*hGlobals)->leftMargin + firstDirty, (Ptr) (pTheScanLine->cIndentDistance));
- }
-
- // Now fill in the last escape sequence command depending upon if we're doing low-res or high-res graphics
-
- pTheScanLine->cEscape = kEscape;
- pTheScanLine->cCommand = (bytesPerBand == 1) ? kLowResGraphicsCommand : kHighResGraphicsCommand;
-
- // If we're doing high-res, then whichCol must be divided by three to compensate for the 3-byte buffer entries
- {
- short adjustedWhichCol = whichCol;
-
- if (bytesPerBand == 3)
- adjustedWhichCol /= 3;
-
- Long2Dec(adjustedWhichCol, (Ptr) (pTheScanLine->cLineStrLength));
- }
-
-
- // Increment the count of the number of bytes that have been added to the buffer
- *bufferPos += kScanLineHdrSize + whichCol;
-
- // Lastly, put a <cr> at the end of the line
- *(buffer + *bufferPos) = '\n';
- *bufferPos += 1;
- }
-
- return(anErr);
- }
- /* SD_RasterPackageBitmap */
-
-
- /****************************************************************************************
-
- SD_RasterLineFeed
-
- function:
- This routine is called by the Printing Manager to send the appropriate line
- feed commands to the printer i norder to skip up or down the page the
- equivalent of lineFeedSize pixels.
-
- parameters:
- lineFeedSize number of pixels to line feed by
- buffer buffer in which to place the linefeed packaging commands
- bufferPos offset within buffer at which to place the linefeed commands
- imageData handle to the raster image data
-
- returns:
- OSErr
-
- ****************************************************************************************/
- OSErr SD_RasterLineFeed(short *lineFeedSize,
- Ptr buffer,
- unsigned long *bufferPos,
- gxRasterImageDataHdl imageData)
- {
- OSErr anErr = noErr;
-
- // If there is no need for any line feeds, then just return now
- if (*lineFeedSize == 0)
- return(anErr);
-
- // If we are in low res mode, we double the line feed size, as all ImageWriter LQ
- // line feed commands are expressed at 144 dpi.
- if ( (*imageData)->vImageRes == ff(72) )
- {
- long longLineFeedSize;
- *lineFeedSize <<= 1;
-
- // do the line feed in the default way
- longLineFeedSize = *lineFeedSize;
- anErr = Forward_GXRasterLineFeed(&longLineFeedSize, buffer, bufferPos, imageData);
- *lineFeedSize = longLineFeedSize;
-
- *lineFeedSize >>= 1;
- }
- else // T => In high res. mode; must determine the number of 1/144 inch and 1/216 inch line feeds needed
- {
- Ptr nextByte;
- Fixed lineFeedInInches;
- Fixed oneOver144;
- Fixed remainder;
- short num216FractLineFeeds;
- Fixed num144FractLineFeeds;
- Str31 aNumber;
-
- // Determine the location at which we'll begin inserting commands
- nextByte = buffer + *bufferPos;
-
- // Is line feed movement going to be backward?
- if ( *lineFeedSize < 0 )
- {
- *lineFeedSize = -(*lineFeedSize); // Force positive
-
- // Add the backward direction command to the buffer
- *nextByte++ = kEscape;
- *nextByte++ = 'r';
- }
- else // T => Paper motion is forward
- {
- // Add the forward direction command to the buffer
- *nextByte++ = kEscape;
- *nextByte++ = 'f';
- }
-
- // Update the count of the number of bytes added to the buffer
- *bufferPos += 2;
-
- // Determine the number of inches we need to skip with the line feed command
- lineFeedInInches = FixDiv( IntToFixed(*lineFeedSize), ff(216) );
-
- // Determine the integral number of 1/144 inch increments the line feed space comprises
-
- oneOver144 = FixDiv(ff(1), ff(144));
- num144FractLineFeeds = FixDiv( lineFeedInInches, oneOver144 );
-
- // Determine the remaining 1/216 inch line feeds we'll need to add to the buffer
-
- remainder = lineFeedInInches - FixMul( IntToFixed( FixedToInt(num144FractLineFeeds) ), oneOver144 );
- num216FractLineFeeds = FixedToInt( FixDiv( remainder, FixDiv( ff(1), ff(216) ) ) );
-
- // Send the line feed spacing commands and the line feeds necessary for the 1/144th's portion of the movement
- {
- short numOne144ths = FixedToInt(num144FractLineFeeds);
-
- if (numOne144ths >= 99) // T => We can do a max. of 99/144 inch movement at a time
- {
- // Add the line feed spacing command to the buffer
- *nextByte++ = kEscape;
- *nextByte++ = 'T';
- *nextByte++ = '9';
- *nextByte++ = '9';
-
- // Update the count of the number of bytes added to the buffer
- *bufferPos += 4;
-
- do
- {
- *nextByte++ = kLineFeed; // line feed
-
- // Update the count of the number of bytes added to the buffer
- *bufferPos += 1;
-
- numOne144ths -= 99;
- }
- while (numOne144ths >= 99);
- }
-
- // Send remaining line feeds to finish off the 1/144th's portion of the movement
-
- if (numOne144ths > 0) // T => Still more movement
- {
- *nextByte++ = kEscape;
- *nextByte++ = 'T';
-
- NumToString(numOne144ths, (unsigned char *) aNumber);
- if ( StrLength(aNumber) == 1 )
- {
- *nextByte++ = '0';
- *nextByte++ = aNumber[1];
- }
- else
- {
- *nextByte++ = aNumber[1];
- *nextByte++ = aNumber[2];
- }
-
- // Add the linefeed character
- *nextByte++ = kLineFeed;
-
- // Update the count of the number of bytes added to the buffer
- *bufferPos += 5;
- }
- }
-
- // Now send any spacing command for the remaining 1/216th portion of the movement if needed
- if (num216FractLineFeeds > 0)
- {
- NumToString(num216FractLineFeeds, (unsigned char *) aNumber);
-
- // Add the command to the buffer: <Esc> t <num line feeds>
-
- *nextByte++ = kEscape;
- *nextByte++ = 't';
- *nextByte = aNumber[1];
-
- // Bump the buffer byte count to account for these new characters
- *bufferPos += 3;
- }
-
- // We always handle the entire linefeed request so we can zero lineFeedSize
- *lineFeedSize = 0;
- }
-
- return(anErr);
- }
- /* SD_RasterLineFeed */
-
-
-